package com.stark.commons.spring.web.boot.config;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.openfeign.support.PageableSpringEncoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.stark.commons.spring.web.boot.properties.FeignProperties;
import com.stark.commons.spring.web.interceptor.FeignHeadersInterceptor;
import com.stark.commons.spring.web.support.feign.FeignErrorDecoder;
import com.stark.commons.spring.web.support.feign.FeignHystrixConcurrencyStrategy;
import com.stark.commons.spring.web.support.feign.JsonQueryMapEncoder;

import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import feign.hystrix.HystrixFeign;

/**
 * feign 自动配置。
 * @author Ben
 * @since 1.0.0
 * @version 1.0.0
 */
@Configuration
@ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignAutoConfiguration")
@EnableCircuitBreaker
@EnableConfigurationProperties(FeignProperties.class)
public class FeignAutoConfig {
	
	@Autowired
	private FeignProperties feignProperties;
	
	@Bean
    @Scope("prototype")
	@ConditionalOnProperty(prefix = "feign.hystrix", name = "enabled", havingValue = "false", matchIfMissing = true)
    public Feign.Builder feignBuilder() {
        return Feign.builder().queryMapEncoder(new JsonQueryMapEncoder());
    }
	
	@Bean
	@Scope("prototype")
	@ConditionalOnProperty(prefix = "feign.hystrix", name = "enabled", havingValue = "true")
	public Feign.Builder feignHystrixBuilder() {
		return HystrixFeign.builder().queryMapEncoder(new JsonQueryMapEncoder());
	}
	
	@Bean
	@ConditionalOnProperty(prefix = "feign.hystrix", name = "enabled", havingValue = "true")
	public HystrixConcurrencyStrategy feignHystrixConcurrencyStrategy() {
		return new FeignHystrixConcurrencyStrategy();
	}
	
	@Bean
	@ConditionalOnWebApplication(type = Type.SERVLET)
	public RequestInterceptor feignHeadersInterceptor() {
		return new FeignHeadersInterceptor(StringUtils.defaultString(feignProperties.getHeadersInclude()).split(","));
	}
	
	@Bean
    @ConditionalOnMissingBean
    @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
    public Encoder springEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new SpringEncoder(messageConverters);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
    public Encoder pageableSpringEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new PageableSpringEncoder(new SpringEncoder(messageConverters));
    }
    
    @Bean
    @ConditionalOnMissingBean
	@ConditionalOnExpression("!'${feign.decode-code}'.isEmpty()")
	public ErrorDecoder errorDecoder() {
		return new FeignErrorDecoder(feignProperties.getDecodeCodes());
	}

}
